package com.jichangxiu.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.jichangxiu.common.annotation.Dynamic;
import com.jichangxiu.common.constant.Constants;
import com.jichangxiu.common.entity.bo.ValidateBos;
import com.jichangxiu.common.exception.ServiceException;
import com.jichangxiu.common.utils.ConvertUtils;
import com.jichangxiu.common.utils.EncodeUtils;
import com.jichangxiu.common.utils.RsaUtils;
import com.jichangxiu.framework.service.impl.BaseServiceImpl;
import com.jichangxiu.framework.utils.DynamicUtils;
import com.jichangxiu.framework.utils.NoUtils;
import com.jichangxiu.framework.utils.SecurityUtils;
import com.jichangxiu.framework.utils.ValidateUtils;
import com.jichangxiu.system.entity.bo.SysRoleMenuBo;
import com.jichangxiu.system.entity.bo.SysUserBo;
import com.jichangxiu.system.entity.dto.SysUserPostDto;
import com.jichangxiu.system.entity.dto.SysUserRoleDto;
import com.jichangxiu.system.entity.dto.add.AddSysUser;
import com.jichangxiu.system.entity.dto.edit.EditSysUser;
import com.jichangxiu.system.entity.dto.query.QuerySysUser;
import com.jichangxiu.system.entity.po.*;
import com.jichangxiu.system.entity.vo.SysPostVo;
import com.jichangxiu.system.entity.vo.SysPowerVo;
import com.jichangxiu.system.entity.vo.SysRoleVo;
import com.jichangxiu.system.entity.vo.SysUserVo;
import com.jichangxiu.system.mapper.SysUserMapper;
import com.jichangxiu.system.service.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * SysUserServiceImpl:
 *
 * @author JiChangXiu
 * @create 2024-06-28 13:44:57
 */
@Service
public class SysUserServiceImpl extends BaseServiceImpl<SysUserMapper, SysUser, SysUserVo> implements SysUserService {

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private SysPostService sysPostService;

    @Resource
    private SysUserPostService sysUserPostService;

    @Resource
    private SysRoleMenuService sysRoleMenuService;

    @Resource
    private SysPowerService sysPowerService;

    /**
     * 新增系统用户
     *
     * @param addSysUser 新增系统用户视图对象
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean add(AddSysUser addSysUser) {
        SysUser sysUser = addAndEditValidBo(ConvertUtils.convert(addSysUser, SysUserBo.class));
        sysUser.setId(IdWorker.getIdStr());
        List<SysUserPost> addSysUserPostList = new ArrayList<>();
        for (String postId : addSysUser.getPostIdList()) {
            addSysUserPostList.add(SysUserPost.builder().userId(sysUser.getId()).postId(postId).tenantId(SecurityUtils.getTenantId()).build());
        }
        List<SysUserRole> addSysUserRoleList = new ArrayList<>();
        for (String roleId : addSysUser.getRoleIdList()) {
            addSysUserRoleList.add(SysUserRole.builder().userId(sysUser.getId()).roleId(roleId).tenantId(SecurityUtils.getTenantId()).build());
        }
        boolean b1 = getBaseMapper().insert(sysUser) > 0;
        boolean b2 = true;
        if (ObjectUtil.isNotEmpty(addSysUserPostList)) {
            b2 = sysUserPostService.saveBatch(addSysUserPostList);
        }
        boolean b3 = true;
        if (ObjectUtil.isNotEmpty(addSysUserRoleList)) {
            b3 = sysUserRoleService.saveBatch(addSysUserRoleList);
        }
        return b1 && b2 && b3;
    }

    /**
     * 单（多）选删除系统用户
     *
     * @param idList 系统用户主键列表
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean del(List<String> idList) {
        boolean b1 = getBaseMapper().deleteBatchIds(delValid(idList)) > 0;
        // 删除用户和角色的关联关系
        boolean b2 = sysUserRoleService.removeBatchByIds(sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, idList)).stream().map(SysUserRole::getId).collect(Collectors.toList()));
        // 删除用户和岗位的关联关系
        boolean b3 = sysUserPostService.removeBatchByIds(sysUserPostService.list(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, idList)).stream().map(SysUserPost::getId).collect(Collectors.toList()));
        return b1 && b2 && b3;
    }

    /**
     * 修改系统用户
     *
     * @param editSysUser 修改系统用户视图对象
     * @return 是否成功
     */
    @Dynamic
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean edit(EditSysUser editSysUser) {
        boolean b1 = getBaseMapper().updateById(addAndEditValidBo(ConvertUtils.convert(editSysUser, SysUserBo.class))) > 0;
        boolean b2 = true;
        // 数据库已存在的
        List<SysUserRole> sysUserRoleList = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, editSysUser.getId()));
        if (!sysUserRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toList()).equals(editSysUser.getRoleIdList())) {
            b2 = sysUserRoleService.addOrDelOrEdit(editSysUser, ConvertUtils.convert(sysUserRoleList, SysUserRoleDto.class));
        }
        boolean b3 = true;
        // 数据库已存在的
        List<SysUserPost> sysUserPostList = sysUserPostService.list(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, editSysUser.getId()));
        if (!sysUserPostList.stream().map(SysUserPost::getPostId).collect(Collectors.toList()).equals(editSysUser.getPostIdList())) {
            b3 = sysUserPostService.addOrDelOrEdit(editSysUser, ConvertUtils.convert(sysUserPostList, SysUserPostDto.class));
        }
        return b1 && b2 && b3;
    }

    /**
     * 根据主键查询系统用户
     *
     * @param id       系统用户主键
     * @param isExtend 是否扩展
     * @return 系统用户详情
     */
    @Dynamic
    @Override
    public SysUserVo info(@NotBlank(message = "主键不能为空") String id, Boolean isExtend) {
        SysUserVo sysUserVo = getBaseMapper().selectJoinOne(SysUserVo.class, buildQueryWrapper(QuerySysUser.builder().id(id).build()));
        if (Boolean.TRUE.equals(isExtend) && ObjectUtil.isNotEmpty(sysUserVo))
            sysUserVo = renderSysUserVoList(ListUtil.toList(sysUserVo)).get(0);
        return sysUserVo;
    }

    /**
     * 根据登录信息查询系统用户
     *
     * @param loginInfo 登录信息
     * @return 系统用户详情
     */
    @Override
    public SysUserVo infoByLoginInfo(String loginInfo) {
        QuerySysUser querySysUser = QuerySysUser.builder().build();
        if (Validator.isMobile(loginInfo))
            // 手机
            querySysUser.setPhone(loginInfo);
        else if (Validator.isEmail(loginInfo))
            // 邮箱
            querySysUser.setEmail(loginInfo);
        else
            // 用户名
            querySysUser.setUsername(loginInfo);
        SysUserVo sysUserVo = selectJoinOne(SysUserVo.class, buildQueryWrapper(querySysUser));
        if (ObjectUtil.isNotEmpty(sysUserVo))
            sysUserVo = renderSysUserVoList(ListUtil.toList(sysUserVo)).get(0);
        return sysUserVo;
    }

    /**
     * （可分页）查询系统用户列表
     *
     * @param querySysUser 查询视图对象
     * @return （分页）系统用户列表
     */
    @Dynamic
    @Override
    public Page<SysUserVo> lists(QuerySysUser querySysUser) {
        Page<SysUserVo> sysUserVoPage = getBaseMapper().selectJoinPage(startPage(), SysUserVo.class, buildQueryWrapper(querySysUser));
        if (Boolean.TRUE.equals(querySysUser.getIsExtend()))
            sysUserVoPage.setRecords(renderSysUserVoList(sysUserVoPage.getRecords()));
        return sysUserVoPage;
    }

    /**
     * 新增 / 修改 前校验
     *
     * @param sysUserBo 校验用业务对象
     * @return 数据库操作对象
     */
    private SysUser addAndEditValidBo(SysUserBo sysUserBo) {
        SysUser sysUser = ConvertUtils.convert(sysUserBo, SysUser.class);
        if (ObjectUtil.isEmpty(sysUser)) {
            throw new ServiceException("待校验对象为空");
        }
        if (!Validator.isEmail(sysUser.getEmail())) {
            throw new ServiceException("邮箱不符合规范");
        }
        if (!Validator.isMobile(sysUser.getPhone())) {
            throw new ServiceException("手机号不符合规范");
        }
        List<ValidateBos> validateBosList = Stream.of(
                ValidateUtils.createNeValidateBos(ValidateUtils.createValidateBo(SysUser::getId, sysUser.getId(), "主键")),
                ValidateUtils.createOrEqValidateBos(
                        ValidateUtils.createValidateBo(SysUser::getNo, sysUser.getNo(), "编码"),
                        ValidateUtils.createValidateBo(SysUser::getCode, sysUser.getCode(), "标识"),
                        ValidateUtils.createValidateBo(SysUser::getName, sysUser.getName(), "名称"),
                        ValidateUtils.createValidateBo(SysUser::getUsername, sysUser.getUsername(), "用户账号"),
                        ValidateUtils.createValidateBo(SysUser::getPhone, sysUser.getPhone(), "电话"),
                        ValidateUtils.createValidateBo(SysUser::getEmail, sysUser.getEmail(), "邮箱"),
                        ValidateUtils.createValidateBo(SysUser::getRemark, sysUser.getRemark(), "备注"))
        ).collect(Collectors.toList());
        // 唯一校验
        ValidateUtils.uniqueValidate(this::countWrapper, validateBosList);
        if (StrUtil.isEmpty(sysUser.getId())) {
            // 新增
            if (Constants.TEN_SUPER_USER.equals(sysUser.getCode())) {
                throw new ServiceException("标识不能为 " + Constants.TEN_SUPER_USER);
            }
            if (Constants.SYS_SUPER_USER.equals(sysUser.getCode())) {
                throw new ServiceException("标识不能为 " + Constants.SYS_SUPER_USER);
            }
            sysUser.setNo(NoUtils.createNo(SecurityUtils.getTenantId(), "user"));
            sysUser.setPassword(EncodeUtils.bcEncode(Constants.JCX_PROPERTIES.getSecurityProperties().getLoginPasswordRsaEnabled() ? RsaUtils.decrypt(sysUser.getPassword()) : sysUser.getPassword()));
            sysUser.setTenantId(SecurityUtils.getUserInfo().getTenantId());
            return sysUser;
        } else {
            // 修改
            SysUser dbSysUser = getById(sysUser.getId());
            if (Constants.TEN_SUPER_USER.equals(sysUser.getCode()) && !sysUser.getCode().equals(dbSysUser.getCode())) {
                throw new ServiceException("标识不能为 " + Constants.TEN_SUPER_USER);
            }
            if (!dbSysUser.getEnabled().equals(sysUser.getEnabled()) && Constants.TEN_SUPER_USER.equals(sysUser.getCode())) {
                throw new ServiceException("标识为 " + Constants.TEN_SUPER_USER + " 的用户状态不能修改");
            }
            if (Constants.SYS_SUPER_USER.equals(sysUser.getCode()) && !sysUser.getCode().equals(dbSysUser.getCode())) {
                throw new ServiceException("标识不能为 " + Constants.SYS_SUPER_USER);
            }
            if (!dbSysUser.getEnabled().equals(sysUser.getEnabled()) && Constants.SYS_SUPER_USER.equals(sysUser.getCode())) {
                throw new ServiceException("标识为 " + Constants.SYS_SUPER_USER + " 的用户状态不能修改");
            }
            if (!dbSysUser.getPassword().equals(sysUser.getPassword())) {
                sysUser.setPassword(EncodeUtils.bcEncode(Constants.JCX_PROPERTIES.getSecurityProperties().getLoginPasswordRsaEnabled() ? RsaUtils.decrypt(sysUser.getPassword()) : sysUser.getPassword()));
            }
            BeanUtil.copyProperties(sysUser, dbSysUser, true);
            return dbSysUser;
        }
    }

    /**
     * 删除前校验
     *
     * @param idList 主键列表
     * @return 主键列表
     */
    private List<String> delValid(List<String> idList) {
        if (ObjectUtil.isEmpty(idList)) {
            throw new ServiceException("待校验主键列表为空");
        }
        List<SysUserBo> sysUserBoList = selectJoinList(SysUserBo.class, buildQueryWrapper(QuerySysUser.builder().idList(idList).build()));
        sysUserBoList.forEach(sysUserBo -> {
            if (Constants.TEN_SUPER_USER.equals(sysUserBo.getCode())) {
                throw new ServiceException("标识为 " + Constants.TEN_SUPER_USER + " 的用户不能删除");
            }
            if (Constants.SYS_SUPER_USER.equals(sysUserBo.getCode())) {
                throw new ServiceException("标识为 " + Constants.SYS_SUPER_USER + " 的用户不能删除");
            }
        });
        return idList;
    }

    /**
     * 渲染视图
     *
     * @param sysUserVoList 视图列表
     * @return 渲染后的视图列表
     */
    private List<SysUserVo> renderSysUserVoList(List<SysUserVo> sysUserVoList) {
        if (ObjectUtil.isNotEmpty(sysUserVoList)) {
            // todo 扩展信息填入
            List<SysUserRole> sysUserRoleList = sysUserRoleService.list(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, sysUserVoList.stream().map(SysUserVo::getId).collect(Collectors.toList())));
            if (ObjectUtil.isNotEmpty(sysUserRoleList)) {
                sysUserVoList.forEach(sysUserVo -> sysUserVo.setRoleIdList(sysUserRoleList.stream().filter(sysUserRole -> sysUserVo.getId().equals(sysUserRole.getUserId())).map(SysUserRole::getRoleId).collect(Collectors.toList())));
                List<SysRole> sysRoleList = sysRoleService.list(new LambdaQueryWrapper<SysRole>().in(SysRole::getId, sysUserRoleList.stream().map(SysUserRole::getRoleId).collect(Collectors.toList())));
                if (ObjectUtil.isNotEmpty(sysRoleList)) {
                    List<SysRoleVo> sysRoleVoList = ConvertUtils.convert(sysRoleList, SysRoleVo.class);
                    sysUserVoList.forEach(sysUserVo -> sysUserVo.setSysRoleVoList(sysRoleVoList.stream().filter(sysRoleVo -> sysUserVo.getRoleIdList().contains(sysRoleVo.getId())).collect(Collectors.toList())));
                }
            }
            List<SysUserPost> sysUserPostList = sysUserPostService.list(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, sysUserVoList.stream().map(SysUserVo::getId).collect(Collectors.toList())));
            if (ObjectUtil.isNotEmpty(sysUserPostList)) {
                sysUserVoList.forEach(sysUserVo -> sysUserVo.setPostIdList(sysUserPostList.stream().filter(sysUserPost -> sysUserVo.getId().equals(sysUserPost.getUserId())).map(SysUserPost::getPostId).collect(Collectors.toList())));
                List<SysPost> sysPostList = sysPostService.list(new LambdaQueryWrapper<SysPost>().in(SysPost::getId, sysUserPostList.stream().map(SysUserPost::getPostId).collect(Collectors.toList())));
                if (ObjectUtil.isNotEmpty(sysPostList)) {
                    List<SysPostVo> sysPostVoList = ConvertUtils.convert(sysPostList, SysPostVo.class);
                    sysUserVoList.forEach(sysUserVo -> sysUserVo.setSysPostVoList(sysPostVoList.stream().filter(sysPostVo -> sysUserVo.getPostIdList().contains(sysPostVo.getId())).collect(Collectors.toList())));
                }
            }

            List<SysPowerVo> sysPowerVoList = new ArrayList<>();
            List<SysRoleMenuBo> sysRoleMenuBoList = sysRoleMenuService.listsByUserId(SecurityUtils.getTenantId(), sysUserVoList.stream().map(SysUserVo::getId).collect(Collectors.toList()));
            if (ObjectUtil.isNotEmpty(sysRoleMenuBoList)) {
                // 权限需要去默认数据库里面获取
                String oldSource = DynamicUtils.currentSource();
                DynamicUtils.setDefaultSource();
                Map<String, List<SysRoleMenuBo>> userIdBySysRoleMenuBoListToMap = sysRoleMenuBoList.stream().collect(Collectors.groupingBy(SysRoleMenuBo::getUserId));
                userIdBySysRoleMenuBoListToMap.forEach((userId, sysRoleMenuBos) -> {
                    List<SysPowerVo> sysPowerVos = sysPowerService.listsByMenuIdList(sysRoleMenuBos.stream().map(SysRoleMenuBo::getMenuId).collect(Collectors.toList()));
                    sysPowerVos.forEach(sysPowerVo -> sysPowerVo.setUserId(userId));
                    sysPowerVoList.addAll(sysPowerVos);
                });
                DynamicUtils.changeSource(oldSource);
            }
            if (ObjectUtil.isNotEmpty(sysPowerVoList)) {
                sysUserVoList.forEach(sysUserVo -> sysUserVo.setSysPowerVoList(sysPowerVoList.stream().filter(sysPowerVo -> sysUserVo.getId().equals(sysPowerVo.getUserId())).collect(Collectors.toList())));
            }
        }
        return sysUserVoList;
    }

    /**
     * 构建查询条件
     *
     * @param querySysUser 查询用业务对象
     * @return 查询条件
     */
    private MPJLambdaWrapper<SysUser> buildQueryWrapper(QuerySysUser querySysUser) {
        MPJLambdaWrapper<SysUser> lambdaQueryWrapper = new MPJLambdaWrapper<SysUser>()
                .selectAll(SysUser.class)
                .leftJoin(SysDept.class, "d", SysDept::getId, SysUser::getDeptId, ext -> ext
                        .selectAs(SysDept::getName, SysUserVo::getDeptName))
                .disableSubLogicDel();
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getId()), SysUser::getId, querySysUser.getId());
        lambdaQueryWrapper.in(ObjectUtil.isNotEmpty(querySysUser.getIdList()), SysUser::getId, querySysUser.getIdList());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getNo()), SysUser::getNo, querySysUser.getNo());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysUser.getCode()), SysUser::getCode, querySysUser.getCode());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysUser.getName()), SysUser::getName, querySysUser.getName());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getUsername()), SysUser::getUsername, querySysUser.getUsername());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getPassword()), SysUser::getPassword, querySysUser.getPassword());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getPhone()), SysUser::getPhone, querySysUser.getPhone());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getEmail()), SysUser::getEmail, querySysUser.getEmail());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysUser.getSex()), SysUser::getSex, querySysUser.getSex());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getAvatar()), SysUser::getAvatar, querySysUser.getAvatar());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getDeptId()), SysUser::getDeptId, querySysUser.getDeptId());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysUser.getSort()), SysUser::getSort, querySysUser.getSort());
        lambdaQueryWrapper.like(StrUtil.isNotEmpty(querySysUser.getRemark()), SysUser::getRemark, querySysUser.getRemark());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysUser.getEnabled()), SysUser::getEnabled, querySysUser.getEnabled());
        lambdaQueryWrapper.eq(StrUtil.isNotEmpty(querySysUser.getEnabledBy()), SysUser::getEnabledBy, querySysUser.getEnabledBy());
        lambdaQueryWrapper.eq(ObjectUtil.isNotEmpty(querySysUser.getEnabledTime()), SysUser::getEnabledTime, querySysUser.getEnabledTime());
        lambdaQueryWrapper.apply(StrUtil.isNotEmpty(querySysUser.getScope()), querySysUser.getScope());
        lambdaQueryWrapper.orderByAsc(SysUser::getSort);
        return lambdaQueryWrapper;
    }

}